package com.moyun.search.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.moyun.search.bo.SearchBO;
import com.moyun.search.common.config.ElasticSearchConfig;
import com.moyun.search.common.result.Result;
import com.moyun.search.common.result.ResultUtil;
import com.moyun.search.domain.FileLab;
import com.moyun.search.vo.SearchResultVO;
import io.searchbox.client.JestClient;
import io.searchbox.core.Search;
import io.searchbox.core.SearchResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 查询服务
 * @author: zealon
 * @since: 2021/12/24
 */
@Slf4j
@Service
public class SearchService {

    @Autowired
    private ElasticSearchConfig elasticSearchConfig;
    @Autowired
    private JestClient jestClient;

    /**
     * 全文查询
     * @param bo
     * @return
     */
    public Result search(SearchBO bo){
        // 计算分页
        int size = bo.getSize();
        int from = (bo.getPage() - 1) * size;

        // 查询体
        JSONObject searchBody = new JSONObject();
        searchBody.put("from", from);
        searchBody.put("size", size);

        // 查询对象
        JSONObject query = new JSONObject();
        JSONObject bool = new JSONObject();
        JSONArray must = new JSONArray();
        JSONObject multi_match = new JSONObject();
        JSONArray fields = new JSONArray();
        fields.add("file_name^10");
        fields.add("attachment.content");

        multi_match.put("query", bo.getKeywords());
        multi_match.put("fields", fields);
        // 关键字匹配
        JSONObject mm = new JSONObject();
        mm.put("multi_match", multi_match);
        must.add(mm);
        // 指定项目ID
        if (bo.getProjectId() != null) {
            must.add(getTermCondition("project_id", bo.getProjectId()));
        }
        // 指定附件类型
        if (bo.getFileType() != null && bo.getFileType().length > 0) {
            must.add(getTermsCondition("file_type", bo.getFileType()));
        }

        bool.put("must", must);
        query.put("bool", bool);
        searchBody.put("query", query);

        // 资源配置
        searchBody.put("_source", this.getSourceConfig());

        // 高亮配置
        searchBody.put("highlight", this.getHighlightConfig());

        // 开始查询
        Search search = new Search.Builder(searchBody.toJSONString())
                .addIndex(elasticSearchConfig.getIndexName())
                .addType(elasticSearchConfig.getType()).build();
        try {
            SearchResult result = jestClient.execute(search);
            if (result.getTotal() == null || result.getTotal() == 0) {
                return ResultUtil.success(Collections.emptyList());
            }
            List<SearchResult.Hit<FileLab, Void>> hitsBooks = result.getHits(FileLab.class);
            List<SearchResultVO> dataList = new ArrayList<>(hitsBooks.size());
            for (SearchResult.Hit<FileLab, Void> hit : hitsBooks) {
                SearchResultVO vo = new SearchResultVO();
                BeanUtils.copyProperties(hit.source, vo);
                this.handleHighlightInfo(hit, vo);
                dataList.add(vo);
            }
            return ResultUtil.success(dataList);
        } catch (IOException e) {
            log.error("查询ES失败！", e);
            return ResultUtil.fail();
        }
    }

    /**
     * 处理高亮信息
     * @param hit
     * @param vo
     */
    private void handleHighlightInfo(SearchResult.Hit<FileLab, Void> hit, SearchResultVO vo) {
        List<String> title = hit.highlight.get("file_name");
        if (title != null && title.size() > 0) {
            vo.setTitle(title.get(0));
        }
        List<String> content = hit.highlight.get("attachment.content");
        if (content != null && content.size() > 0) {
            vo.setContent(content.get(0));
        }
    }

    private JSONObject getHighlightConfig() {
        JSONObject highlight = new JSONObject();
        highlight.put("encoder", "html");

        JSONArray pre_tags_vals = new JSONArray();
        pre_tags_vals.add("<b style='color:red; background-color:#DEF742'>");
        highlight.put("pre_tags", pre_tags_vals);
        JSONArray post_tags_vals = new JSONArray();
        post_tags_vals.add("</b>");
        highlight.put("post_tags", post_tags_vals);

        JSONObject fields = new JSONObject();
        JSONObject file_name = new JSONObject();
        JSONObject attachmentContent = new JSONObject();
        fields.put("file_name", file_name);
        fields.put("attachment.content", attachmentContent);
        highlight.put("fields", fields);
        return highlight;
    }

    private JSONObject getSourceConfig() {
        JSONObject _source = new JSONObject();
        JSONArray excludes = new JSONArray();
        excludes.add("attachment.content");
        _source.put("excludes", excludes);
        return _source;
    }

    /**
     * 获取Term字段条件
     * @param fieldName 字段名称
     * @param value     值
     * @return
     */
    private JSONObject getTermCondition(String fieldName, Object value){
        JSONObject field = new JSONObject();
        JSONObject term  = new JSONObject();
        term.put(fieldName, value);
        field.put("term", term);
        return field;
    }

    /**
     * 获取Terms字段条件
     * @param fieldName 字段名称
     * @param value     值
     * @return
     */
    private JSONObject getTermsCondition(String fieldName, String[] value){
        JSONObject field = new JSONObject();
        JSONObject term  = new JSONObject();
        term.put(fieldName, value);
        field.put("terms", term);
        return field;
    }
}